package ms.jasim.framework.test;

import java.io.IOException;
import java.util.ArrayList;

import ms.jasim.model.Actor;
import ms.jasim.model.Capability;
import ms.jasim.model.Decomposition;
import ms.jasim.model.Dependency;
import ms.jasim.model.Goal;
import ms.jasim.model.GoalRequest;
import ms.jasim.model.JasimModel;
import ms.jasim.model.ModelFactory;
import ms.jasim.pddl.BrylPddlGenerator;
import ms.jasim.pddl.JasimOrgPddlGenerator;
import ms.jasim.pddl.PddlProblem;

public class GenTestFilePattern1 {
	
	
	private JasimModel model;
	private String fileSuffix;
	private ArrayList<Goal> leafGoals;
	
	public GenTestFilePattern1(int numTree, boolean multiTree) {
		this.model = ModelFactory.eINSTANCE.createJasimModel();
		this.leafGoals = new ArrayList<Goal>();
	}
	
	public GenTestFilePattern1(int numTree, int numActor, int overlapFactor, int goalDepth, int goalFanOut) {
		this.model = ModelFactory.eINSTANCE.createJasimModel();
		this.leafGoals = new ArrayList<Goal>();
		// create goals
		
		this.fileSuffix = "_" + String.format("%dx%d", goalDepth, goalFanOut);
		generate(numTree, numActor, overlapFactor, goalDepth, goalFanOut);
	}

	public GenTestFilePattern1 generate(int numTree, int numActor, int overlapFactor, int goalDepth, int goalFanOut) {
		generateActors(numActor, overlapFactor);
		for (int i = 1; i <= numTree; i++)
			generateGoals("T" + i +"_", null, 0, goalDepth, goalFanOut);
		generateDepenencies();
		generateCapabilities();
		return this;
	}

	
	protected void generateCapabilities() {
		int actIdx = 0;
		int N = model.getActors().size();
		for(Goal g: leafGoals) {
			Capability cap1 = ModelFactory.eINSTANCE.createCapability();
			Capability cap2 = ModelFactory.eINSTANCE.createCapability();
			
			cap1.setGoal(g);
			cap2.setGoal(g);
			
			model.getActors().get(actIdx).getCapability().add(cap1);
			model.getActors().get((actIdx + 1) % N).getCapability().add(cap2);
			
			actIdx = (actIdx + 2) % N;
		}
	}

	protected void generateActors(int numActor, int overlapFactor) {
		if (numActor <= 0)
			return;
		/*int numOfAvgCap = leafGoals.size() / numActor;
		if (numOfAvgCap == 0)
			numOfAvgCap = 1;
		int pad = leafGoals.size() - numOfAvgCap * numActor;
		if (pad < 0)
			pad = 0;*/
					
		for(int i = 0; i < numActor; i++) {
			Actor a = ModelFactory.eINSTANCE.createActor();
			a.setName("A" + (i + 1));
			model.getActors().getActor().add(a);
			
			/*// generate request
			if (i==0) {
				GoalRequest req = ModelFactory.eINSTANCE.createGoalRequest();
				req.setGoal(model.getGoals().get(0));
				a.getRequests().add(req);
			}
			// generate capability
			if (overlapFactor == -1) overlapFactor = numOfAvgCap;
			
			int N = numOfAvgCap + overlapFactor + (i == numActor - 1? pad: 0);
			for (int j = i*numOfAvgCap; N > 0; j++, N--) {
				Capability cap = ModelFactory.eINSTANCE.createCapability();
				cap.setGoal(leafGoals.get(j % leafGoals.size()));
				a.getCapability().add(cap);
			}*/
		}
	}

	protected void generateGoals(String goalName, Goal parent, int currentDepth, int goalDepth, int goalFanOut) {
		if (parent == null) {
			Goal root = ModelFactory.eINSTANCE.createGoal();
			root.setName(goalName);
			model.getGoals().getGoal().add(root);
			generateGoals(goalName, root, 1, goalDepth, goalFanOut);
			
			// create a request for this goal
			GoalRequest req = ModelFactory.eINSTANCE.createGoalRequest();
			req.setGoal(root);
			model.getActors().get(0).getRequests().add(req);
		}
		else {
			ArrayList<Goal> children = new ArrayList<Goal>();
			for (int i = 1; i <= goalFanOut; i++) {
				Goal child = ModelFactory.eINSTANCE.createGoal();
				child.setName(parent.getName() + i);
				model.getGoals().getGoal().add(child);
				children.add(child);
				if (currentDepth < goalDepth)
					generateGoals(goalName, child, currentDepth + 1, goalDepth, goalFanOut);
				else
					leafGoals.add(child);
				
				// create goal relationship
				/*switch(goalFanOut%3) {
				case 0:
					for(int j = 0; j < goalFanOut / 3; j++) {
						Decomposition de = ModelFactory.eINSTANCE.createDecomposition();
						
					}
					break;
				case 1:
				case 2:
				}*/
			}
			// create goal relationship
			for(int size = 0, sIdx = 0, N = children.size(); N > 0; N -= size, sIdx += size) {
				size = N >= 5 || N == 3 ? 3 : 2;
				Decomposition de = ModelFactory.eINSTANCE.createDecomposition();
				for (int j = sIdx; j < sIdx + size; j++)
					de.getSubGoals().add(children.get(j));
				parent.getDecomposition().add(de);
			}
		}
	}

	protected void generateDepenencies() {
		Actor requestor = model.getActors().get(0);
		for (int i = 1; i < model.getActors().size(); i++) {
			Actor provider = model.getActors().get(i);
			Dependency de = ModelFactory.eINSTANCE.createDependency();
			de.getTargetActor().add(provider);
			requestor.getDependency().add(de);
		}
	}
	
	public int save(String filename) throws IOException {
		String pddlFilename = filename + fileSuffix + ".pddl";
		String oldPddlFilename = filename + fileSuffix + ".bpddl";
		
		if (!filename.endsWith(".jasim"))
			filename += fileSuffix + ".jasim";
		/*Resource resource = new XMIResourceImpl(URI.createURI(filename));
        
		resource.getContents().add(model);

		try {
			resource.save(null);
		} catch (IOException e) {
			e.printStackTrace();
		}*/
		
		System.out.println(filename);
		System.out.println("\tactors: " + model.getActors().size());
		System.out.println("\tgoals: " + model.getGoals().size());
		System.out.println("\tleaf goals: " + leafGoals.size());
		
		PddlProblem pddlProblem = new JasimOrgPddlGenerator().getPddlProblem(model);
		pddlProblem.writeToFile(pddlFilename);
		
		System.out.println("\tJasim predicates: " + pddlProblem.facts.size());
		
		PddlProblem pddlProblem2 = new BrylPddlGenerator().getPddlProblem(model);
		pddlProblem2.writeToFile(oldPddlFilename);
		
		System.out.println("\tBryl predicates: " + pddlProblem2.facts.size());
		
		return model.getGoals().size();
	}
	
	public static void main(String[] args) throws IOException {
		
	}
}
